/*
 * NodeFactory
 *
 * Created on 25. August 2004, 00:09
 *
 * Copyright (c) 2004, 2005 Ansgar Konermann
 * Contact: <konermann@itikko.net>
 *
 * This file is part of the OCL2.0 parser and compiler libraries
 * created at Technische Universitaet Dresden (TUD), Germany.
 * Visit http://dresden-ocl.sourceforge.net/ for details.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA  02111-1307  USA
 *
 */

/**
 * Adapted for einaGMC's software by Antonio Villegas
 */

package parser.astgen;


import parser.astlib.*;

import java.util.*;

import facade.kernel.OperationFacade;
import facade.kernel.ParameterFacade;
import facade.kernel.PropertyFacade;
import facade.ocl.AnyTypeFacade;
import facade.ocl.AssociationClassCallExpFacade;
import facade.ocl.BagTypeFacade;
import facade.ocl.BooleanLiteralExpFacade;
import facade.ocl.CollectionItemFacade;
import facade.ocl.CollectionLiteralExpFacade;
import facade.ocl.CollectionRangeFacade;
import facade.ocl.EnumLiteralExpFacade;
import facade.ocl.IfExpFacade;
import facade.ocl.IntegerLiteralExpFacade;
import facade.ocl.IterateExpFacade;
import facade.ocl.IteratorExpFacade;
import facade.ocl.LetExpFacade;
import facade.ocl.OperationCallExpFacade;
import facade.ocl.OrderedSetTypeFacade;
import facade.ocl.PropertyCallExpFacade;
import facade.ocl.RealLiteralExpFacade;
import facade.ocl.SequenceTypeFacade;
import facade.ocl.SetTypeFacade;
import facade.ocl.StringLiteralExpFacade;
import facade.ocl.TupleLiteralExpFacade;
import facade.ocl.TupleLiteralPartFacade;
import facade.ocl.TupleTypeFacade;
import facade.ocl.TypeExpFacade;
import facade.ocl.VariableExpFacade;
import facade.ocl.VariableFacade;
import project.Project;


/**
 *
 * Abstract factory which creates instances of AST nodes specified
 * by name.
 *
 * @author Antonio Villegas
 * @version
 */
public class NodeFactory extends Object {
	
	// GMC: Facade classes for construct the UML and OCL elements
    private Project p;
    private OperationCallExpFacade ocef;
    private IntegerLiteralExpFacade ilef;
    private RealLiteralExpFacade rlef;
    private BooleanLiteralExpFacade blef;
    private StringLiteralExpFacade slef;
    private IfExpFacade ifef;
    private IteratorExpFacade itef;
    private IterateExpFacade iteef;
    private VariableFacade vf;
    private VariableExpFacade vef;
    private OperationFacade of;
    private CollectionLiteralExpFacade clef;
    private SetTypeFacade stf;
    private SequenceTypeFacade setf;
    private BagTypeFacade btf;
    private OrderedSetTypeFacade ostf;
    private PropertyCallExpFacade pcef;
    private TupleTypeFacade ttf;
    private TupleLiteralPartFacade tlpf;
    private TupleLiteralExpFacade tlef;
    private TypeExpFacade tef;
    private AssociationClassCallExpFacade accef;
    private PropertyFacade pf;
    private LetExpFacade lef;
    private CollectionRangeFacade crf;
    private CollectionItemFacade cif;
    private ParameterFacade parf;
    private AnyTypeFacade atf;
    private EnumLiteralExpFacade elef;
    
    public NodeFactory(Project p) {
  
    	this.p = p;
    	this.ocef = new OperationCallExpFacade(this.p);
    	this.ilef = new IntegerLiteralExpFacade(this.p);
    	this.rlef = new RealLiteralExpFacade(this.p);
    	this.blef = new BooleanLiteralExpFacade(this.p);
    	this.slef = new StringLiteralExpFacade(this.p);
    	this.ifef = new IfExpFacade(this.p);
    	this.itef = new IteratorExpFacade(this.p);
    	this.iteef = new IterateExpFacade(this.p);
    	this.vf   = new VariableFacade(this.p);
    	this.vef  = new VariableExpFacade(this.p);
    	this.of   = new OperationFacade(this.p);
    	this.clef = new CollectionLiteralExpFacade(this.p);
    	this.stf  = new SetTypeFacade(this.p);
    	this.pcef = new PropertyCallExpFacade(this.p);
    	this.setf = new SequenceTypeFacade(this.p);
    	this.btf  = new BagTypeFacade(this.p);
    	this.ostf = new OrderedSetTypeFacade(this.p);
    	this.tef  = new TypeExpFacade(this.p);
    	this.accef = new AssociationClassCallExpFacade(this.p);
    	this.ttf  = new TupleTypeFacade(this.p);
    	this.tlpf  = new TupleLiteralPartFacade(this.p);
    	this.tlef  = new TupleLiteralExpFacade(this.p);
    	this.pf   = new PropertyFacade(this.p);
    	this.lef  = new LetExpFacade(this.p);
    	this.crf = new CollectionRangeFacade(this.p);
    	this.cif = new CollectionItemFacade(this.p);
    	this.parf = new ParameterFacade(this.p);
    	this.atf = new AnyTypeFacade(this.p);
    	this.elef = new EnumLiteralExpFacade(this.p);
    	
        initialize();
    }
    
    private abstract static class Ctor {
        public abstract Object cr();
    }
    
    private Map creatorsByType = new HashMap();
    
    /**
     * initializes the HashMap with 
     */
    private void initialize() {
        Map c = creatorsByType;
        
        // Java elements
        c.put("Object",                 new Ctor() { public Object cr() { return new Object(); } } );
        c.put("List",                   new Ctor() { public Object cr() { return new java.util.LinkedList(); } } );
        
        // GMC elements
        c.put("OperationCallExp",       new Ctor() { public Object cr() { return ocef.createOperationCallExp(); } } );
        c.put("IntegerLiteralExp",      new Ctor() { public Object cr() { return ilef.createIntegerLiteralExp(); } } );
        c.put("RealLiteralExp",         new Ctor() { public Object cr() { return rlef.createRealLiteralExp(); } } );      
        c.put("BooleanLiteralExp",      new Ctor() { public Object cr() { return blef.createBooleanLiteralExp(); } } );
        c.put("StringLiteralExp",       new Ctor() { public Object cr() { return slef.createStringLiteralExp(); } } );
        c.put("IfExp",      		    new Ctor() { public Object cr() { return ifef.createIfExp(); } } );
        c.put("IteratorExp",      		new Ctor() { public Object cr() { return itef.createIteratorExp(); } } );
        c.put("IterateExp",      		new Ctor() { public Object cr() { return iteef.createIterateExp(); } } );
        c.put("Variable",        		new Ctor() { public Object cr() { return vf.createVariable(); } } );
        c.put("VariableExp",      		new Ctor() { public Object cr() { return vef.createVariableExp(); } } );
        c.put("Operation",      		new Ctor() { public Object cr() { return of.createOperation(); } } );
        c.put("CollectionLiteralExp",   new Ctor() { public Object cr() { return clef.createCollectionLiteralExp(); } } );
        c.put("CollectionRange",   		new Ctor() { public Object cr() { return crf.createCollectionRange(); } } );
        c.put("CollectionItem",   		new Ctor() { public Object cr() { return cif.createCollectionItem(); } } );
        c.put("SetType",                new Ctor() { public Object cr() { return stf.createSetType(); } } );
        c.put("PropertyCallExp",        new Ctor() { public Object cr() { return pcef.createPropertyCallExp(); } } );
        c.put("SequenceType",           new Ctor() { public Object cr() { return setf.createSequenceType(); } } );
        c.put("BagType",                new Ctor() { public Object cr() { return btf.createBagType(); } } );
        c.put("OrderedSetType",         new Ctor() { public Object cr() { return ostf.createOrderedSetType(); } } );
        c.put("TypeExp",                new Ctor() { public Object cr() { return tef.createTypeExp(); } } );
        c.put("AssociationClassCallExp",new Ctor() { public Object cr() { return accef.createAssociationClassCallExp(); } } );
        c.put("TupleType",				new Ctor() { public Object cr() { return ttf.createTupleType(); } } );
        c.put("TupleLiteralPart",		new Ctor() { public Object cr() { return tlpf.createTupleLiteralPart(); } } );
        c.put("TupleLiteralExp",		new Ctor() { public Object cr() { return tlef.createTupleLiteralExp(); } } );
        c.put("Property",				new Ctor() { public Object cr() { return pf.createProperty(); } } );
        c.put("LetExp",					new Ctor() { public Object cr() { return lef.createLetExp(); } } );
        c.put("Parameter",				new Ctor() { public Object cr() { return parf.createParameter(); } } );
        c.put("AnyType",				new Ctor() { public Object cr() { return atf.createAnyType(); } } );
        c.put("EnumLiteralExp",			new Ctor() { public Object cr() { return elef.createEnumLiteralExp(); } } );
        
        // parser.astlib.* elements
        c.put("OclFormalParameter",     new Ctor() { public Object cr() { return new OclFormalParameter(); } } );        
        c.put("OclSignalSpec",              new Ctor() { public Object cr() { return new OclSignalSpec(); } } );
        c.put("OclBinaryExpTail",           new Ctor() { public Object cr() { return new OclBinaryExpTail(); } } );
        c.put("OclOperationSignature",      new Ctor() { public Object cr() { return new OclOperationSignature(); } } );
        c.put("OclOperationConstraint",     new Ctor() { public Object cr() { return new OclOperationConstraint(); } } );
        c.put("OclOperationContextDecl",    new Ctor() { public Object cr() { return new OclOperationContextDecl(); } } );
        c.put("OclAttributeDefinedEntityDecl",  new Ctor() { public Object cr() { return new OclAttributeDefinedEntityDecl(); } } );
        c.put("OclOperationDefinedEntityDecl",  new Ctor() { public Object cr() { return new OclOperationDefinedEntityDecl(); } } );
        c.put("OclClassifierContextDecl",           new Ctor() { public Object cr() { return new OclClassifierContextDecl(); } } );
        c.put("OclDefinitionClassifierConstraint",  new Ctor() { public Object cr() { return new OclDefinitionClassifierConstraint(); } } );
        c.put("OclInvariantClassifierConstraint",   new Ctor() { public Object cr() { return new OclInvariantClassifierConstraint(); } } );
        c.put("OclDefinitionConstraint",    new Ctor() { public Object cr() { return new OclDefinitionConstraint(); } } );
        c.put("OclPackagedConstraintList",  new Ctor() { public Object cr() { return new OclPackagedConstraintList(); } } );
        c.put("OclAttrOrAssocContextDecl",  new Ctor() { public Object cr() { return new OclAttrOrAssocContextDecl(); } } );
        c.put("OclInitConstraint",          new Ctor() { public Object cr() { return new OclInitConstraint(); } } );
        c.put("OclDeriveConstraint",        new Ctor() { public Object cr() { return new OclDeriveConstraint(); } } );
        c.put("OclActualParameterListItem", new Ctor() { public Object cr() { return new OclActualParameterListItem(); } } );
        
    }

    /**
     * Method for create objects 
     * @param typeName the name of the class to create the instance
     * @return the object of the class named 'typename'
     */
    public Object createNode(String typeName) {   
        Ctor cr = (Ctor) creatorsByType.get(typeName);
        if ( cr == null ) {
            throw new RuntimeException("No creator for type '" + typeName + "' in abstract factory " + this.getClass().getName());
        }
        return cr.cr();
    }    
}
